package com.hup.minicontroller.client.service;

import android.os.Build;
import android.util.Log;

import com.hup.minicontroller.client.ClientApplication;
import com.hup.minicontroller.client.model.AppConfig;
import com.hup.minicontroller.client.model.AppState;
import com.hup.minicontroller.client.mvp.IClientHandler;
import com.hup.minicontroller.client.mvp.IMainView;
import com.hup.minicontroller.common.constant.ControlActionConstant.FunctionButton;
import com.hup.minicontroller.common.constant.NetConstant.ConnectType;
import com.hup.minicontroller.common.model.dto.ControlConfigDto;
import com.hup.minicontroller.common.model.dto.FullScreenTouchRequest;
import com.hup.minicontroller.common.model.dto.FunctionButtonRequest;
import com.hup.minicontroller.common.model.dto.LoginRequest;
import com.hup.minicontroller.common.model.dto.LoginResponse;
import com.hup.minicontroller.common.model.dto.TouchPadTouchRequest;
import com.hup.minicontroller.common.netty.NettyTCPClient;
import com.hup.minicontroller.common.netty.NettyTCPClient.ClientCallback;
import com.hup.minicontroller.common.netty.NettyTCPClient.ClientConfig;
import com.hup.minicontroller.common.netty.NettyTCPClient.ConnectState;
import com.hup.minicontroller.common.netty.handler.DataCodecHandler;
import com.hup.minicontroller.common.netty.handler.HeartbeatHandler;
import com.hup.minicontroller.common.netty.handler.HeartbeatHandler.IdleCallback;
import com.hup.minicontroller.common.netty.handler.LoginResponseHandler;
import com.hup.minicontroller.common.netty.handler.dataListener.NetSpeedListener;
import com.hup.minicontroller.common.netty.model.LoginResponsePacket;

import java.util.Locale;

import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.timeout.IdleStateEvent;
import lombok.Getter;

/**
 * wifi和热点)局域网client
 */
public class LanClientService implements IClientHandler {
    private static final String TAG = LanClientService.class.getSimpleName();

    private final AppState appState;
    private final ClientConfig clientConfig;
    private final NettyTCPClient client;
    private final NetSpeedListener netSpeedListener;

    @Getter
    private ConnectType connectType = ConnectType.LAN;

    LanClientService(DataHandlerService dataHandlerService) {
        appState = ClientApplication.getBean(MainService.class).getAppState();
        MyClientCallback clientCallback = new MyClientCallback();
        clientConfig = new ClientConfig(clientCallback);
        clientConfig.setConnectTimeout(3000);
        clientConfig.loginHandler(clientCallback)
                .setAddHeartbeat(true, clientCallback)
                .addDataHandler(dataHandlerService);
        client = new NettyTCPClient(clientConfig);
        netSpeedListener = new NetSpeedListener();
        DataCodecHandler.INSTANCE.addDataListener(netSpeedListener);
    }

    @Override
    public void switchClient(boolean isConnect) {
        Log.i(TAG, "switchClient: " + isConnect);
        if (isConnect) {
            AppConfig appConfig = appState.getAppConfig();
            clientConfig.target(appConfig.getLanInputIp(), appConfig.getLanServerPort());
            client.connect();
        } else {
            client.disconnect();
        }
    }

    @Override
    public void onControlConfigChanged() {
        if (client.getConnectState() != ConnectState.CONNECTED) return;
        Log.i(TAG, "onControlConfigChanged: ");
        client.send(appState.getControlConfig());
    }

    @Override
    public void onFunctionButton(FunctionButton button) {
        if (client.getConnectState() != ConnectState.CONNECTED) return;
        Log.i(TAG, "onFunctionButton: " + button.desc);
        client.send(new FunctionButtonRequest(button.index));
    }

    @Override
    public void onFullScreenTouch(FullScreenTouchRequest fullScreenTouchRequest) {
        if (client.getConnectState() != ConnectState.CONNECTED) return;
        //Log.i(TAG, "onFullScreenTouch: ");
        client.send(fullScreenTouchRequest);
    }

    @Override
    public void onTouchPadTouch(TouchPadTouchRequest touchPadTouch) {
        if (client.getConnectState() != ConnectState.CONNECTED) return;
        //Log.i(TAG, "touchPadTouch: ");
        client.send(touchPadTouch);
    }

    @Override
    public void doTerminate() {
        Log.i(TAG, "doTerminate: ");
        client.doTerminate();
    }

    @Override
    public void getSpeedText(StringBuilder sb) {
        if (client.getConnectState() != ConnectState.CONNECTED) return;
        netSpeedListener.updateSpeed();
        sb.append(String.format(Locale.getDefault(), "局域网  发送: %dKB/s, 接收: %dKB/s", netSpeedListener.getSendSpeed(), netSpeedListener.getReceiveSpeed()));
    }

    private class MyClientCallback extends LoginResponseHandler<LoginRequest, LoginResponse> implements ClientCallback, IdleCallback {

        @Override
        public void onConnectResult(boolean success, String host, Integer port, LoginResponsePacket loginResponse) {
            Log.i(TAG, "onConnectResult: " + success + ", host=" + host + ", loginResponse=" + loginResponse);
            if (success) {
                LoginResponse response = (LoginResponse) loginResponse;
                appState.setConnectedType(getConnectType());
                appState.setServerName(response.getServerName());
                appState.setLanServerHost(host);
                ControlConfigDto controlConfig = response.getControlConfig();
                if (controlConfig != null) appState.getControlConfig().apply(controlConfig);
            } else {
                appState.onDisconnect();
            }
            ClientApplication.executeIfExist(IMainView.class, iMainView -> iMainView.onConnectResult(loginResponse));
        }

        @Override
        public void onConnectionLost() {
            Log.i(TAG, "onConnectionLost: ");
            appState.onDisconnect();
            ClientApplication.executeIfExist(IMainView.class, IMainView::onConnectionLost);
            ClientApplication.executeIfExist(LanBroadcastReceiverService.class, s -> s.switchService(true));
            ClientApplication.executeIfExist(BluetoothDeviceService.class, s -> s.switchService(true));
        }

        @Override
        public Class<LoginResponse> getLoginResponseType() {
            return LoginResponse.class;
        }

        @Override
        public LoginRequest getLoginValidData() {
            LoginRequest loginRequest = new LoginRequest();
            loginRequest.setName(Build.MODEL);
            Log.i(TAG, "getLoginValidData: " + loginRequest);
            return loginRequest;
        }

        @Override
        public void onChannelIdle(ChannelHandlerContext ctx, IdleStateEvent e) {
            Log.i(TAG, "onChannelIdle: 无收到消息=" + HeartbeatHandler.getReaderIdleTimeSeconds() + "秒,主动关闭连接");
            ctx.channel().close();
            ClientApplication.executeIfExist(IMainView.class, IMainView::onChannelIdle);
        }
    }

}
